#include <glib/gi18n.h>
#include <gtk/gtk.h>
#include "demo.h"

typedef struct
{
    cairo_operator_t op_type;
    gchar* desc;    
} PorterDuffOperator_t;

//A指代source, B指代dest, R指代result
//x指代color中的r/g/b分量, a指代alpha分量
//xaA指代xA和aA的乘积
static PorterDuffOperator_t operators[]=
{
    {CAIRO_OPERATOR_CLEAR,"Clear: aR=0, xR=0"},

    {CAIRO_OPERATOR_SOURCE,"Source: aR=aA, xR=xA"},
    {CAIRO_OPERATOR_OVER,"Over: aR=aA+aB·(1-aA), xR=(xaA+xaB·(1-aA))/aR"},
    {CAIRO_OPERATOR_IN,"In: aR=aA*aB, xR=xA"},
    {CAIRO_OPERATOR_OUT,"Out: aR=aA*(1-aB), xR=xA"},
    {CAIRO_OPERATOR_ATOP,"Atop: aR=aA, xR=xaA+xB(1-aA)"},

    {CAIRO_OPERATOR_DEST,"Dest: aR=aB, xR=xB"},
    {CAIRO_OPERATOR_DEST_OVER,"DestOver: aR=(1-aB)·aA+aB, xR=(xaA·(1-aB)+xaB)/aR"},
    {CAIRO_OPERATOR_DEST_IN,"In: aR=aA·aB, xR=xB"},
    {CAIRO_OPERATOR_DEST_OUT,"Out: aR=(1-aA)·aB, xR=xB"},
    {CAIRO_OPERATOR_DEST_ATOP,"Atop: aR=aA, xR=xA·(1-aB)+xaB"},

    {CAIRO_OPERATOR_XOR,"Xor: aR=aA+aB-2·aA·aB xR=(xaA·(1-aB) +xaB·(1-aA))/aR"},
    {CAIRO_OPERATOR_ADD,"Add: aR=min(1, aA+aB), xR=(xaA + xaB)/aR"},
    {CAIRO_OPERATOR_SATURATE,"Saturate: aR=min(1, aA+aB), xR=(min(aA, 1-aB)·xA + xaB)/aR"},

    //aR = aA + aB·(1−aA)
    //xR = 1/aR · [ (1−aB)·xaA + (1−aA)·xaB + aA·aB·f(xA,xB) ]
    {CAIRO_OPERATOR_MULTIPLY,"Multiply: f(xA,xB)=xA·xB"},
    {CAIRO_OPERATOR_SCREEN,"Screen: f(xA,xB)= xA + xB - xA·xB"},
    {CAIRO_OPERATOR_OVERLAY,"Overlay: f(xA,xB)= (xB ≤ 0.5) ? 2·xA·xB : 1-2·(1-xA)·(1-xB)"},
    {CAIRO_OPERATOR_DARKEN,"Darken: f(xA,xB)=min(xA,xB)"},
    {CAIRO_OPERATOR_LIGHTEN,"Lighten: f(xA,xB)=max(xA,xB)"},
    {CAIRO_OPERATOR_COLOR_DODGE,"ColorDodge: f(xA,xB)=(xA<1) ? min(1, xB/(1−xA)) : 1"},
    {CAIRO_OPERATOR_COLOR_BURN,"ColorBurn: f(xA,xB)=(xA>0) ?  1-min(1,(1-xB)/xA) : 0"},
    {CAIRO_OPERATOR_HARD_LIGHT,"HardLight: f(xA,xB)=(xA≤0.5) ? 2·xA·xB : 1-2·(1-xA)·(1-xB)"},
    {CAIRO_OPERATOR_SOFT_LIGHT,"SoftLigt: f(xA,xB)="},
    {CAIRO_OPERATOR_DIFFERENCE,"Difference: f(xA,xB)=abs(xB-xA)"},
    {CAIRO_OPERATOR_EXCLUSION,"Exclusion: f(xA,xB)=xA+xB-2·xA·xB"},

    {CAIRO_OPERATOR_HSL_HUE,"HslHue"},
    {CAIRO_OPERATOR_HSL_SATURATION,"Saturation"},
    {CAIRO_OPERATOR_HSL_COLOR,"Color"},
    {CAIRO_OPERATOR_HSL_LUMINOSITY,"Luminosity"},

};

static gboolean on_draw(GtkWidget *widget, cairo_t *cr, gpointer data)
{
    PorterDuffOperator_t *p = data;

    guint width, height;
    // GdkRGBA color;
    GtkStyleContext *context;


    context = gtk_widget_get_style_context (widget);

    width = gtk_widget_get_allocated_width (widget);
    height = gtk_widget_get_allocated_height (widget);

    g_print("on_draw()....width=%d,height=%d\n", width, height);

    gtk_render_background (context, cr, 0, 0, width, height);



	cairo_rectangle (cr, 0, 0, 120, 90);
	cairo_set_source_rgba (cr, 0.7, 0, 0, 0.8);
	cairo_fill (cr);

    // cairo_operator_t old = cairo_get_operator(cr);
    cairo_save(cr);

    cairo_set_operator (cr, p->op_type);

	cairo_rectangle (cr, 40, 30, 120, 90);
	cairo_set_source_rgba (cr, 0, 0, 0.9, 0.4);
	cairo_fill (cr);

    // cairo_set_operator (cr, old);
    cairo_restore(cr);

    cairo_rectangle(cr, 0,0, width, height);
    cairo_set_line_width (cr, 5);
    cairo_set_source_rgba(cr, 0,0,0, 1);
    cairo_stroke(cr);

    cairo_move_to(cr, 200, 50);
    cairo_set_font_size(cr, 12);
    cairo_text_path(cr, p->desc);
    // cairo_set_line_width (cr, 1);
    cairo_set_source_rgba(cr, 0,0,0, 1);
    cairo_fill(cr);

    return FALSE;
}

void do_operator(GtkBox *parent)
{
    GtkWidget* frame;
    GtkWidget* scroll;
    // GtkWidget* grid;
    GtkWidget* box;
    GtkWidget* drawing_area;

    frame = gtk_frame_new("Porter/Duff compositing operator");
    gtk_container_set_border_width(GTK_CONTAINER(frame), 10);
    gtk_box_pack_start(parent, frame, TRUE, TRUE, 0);

    scroll = gtk_scrolled_window_new(NULL, NULL);
    gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
    gtk_widget_set_hexpand(scroll, FALSE);
    gtk_widget_set_vexpand(scroll, TRUE);
    gtk_container_add(GTK_CONTAINER(frame), scroll);

    // grid = gtk_grid_new();
    // gtk_container_add(GTK_CONTAINER(frame), grid);

    box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 5);
    gtk_container_add(GTK_CONTAINER(scroll), box);

    for(int i = 0; i< G_N_ELEMENTS(operators); i++)
    {
        PorterDuffOperator_t *p = &operators[i];

        drawing_area = gtk_drawing_area_new();
        gtk_widget_set_size_request(drawing_area, 200,200);
        // gtk_grid_attach(GTK_GRID(grid), drawing_area, i/2, i%2, 1, 1);
        gtk_container_add(GTK_CONTAINER(box), drawing_area);
        g_signal_connect(drawing_area, "draw", G_CALLBACK (on_draw), p);        
    }

    gtk_widget_show_all(GTK_WIDGET(parent));    
}